package carassius.DAL;

import carassius.BLL.Events.WaterMeasurement.WaterMeasurementAddedListener;
import carassius.BLL.Events.WaterMeasurement.WaterMeasurementAddedPublisher;
import carassius.BLL.Events.WaterMeasurement.WaterMeasurementRemovedListener;
import carassius.BLL.Events.WaterMeasurement.WaterMeasurementRemovedPublisher;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author siebz0r
 */
public class WaterMeasurementTable
		extends ActionTable<WaterMeasurementRow>
		implements WaterMeasurementAddedPublisher,
				   WaterMeasurementRemovedPublisher
{
	//<editor-fold defaultstate="collapsed" desc="Fields">
	private final ArrayList<WaterMeasurementAddedListener> _waterMeasurementAddedListeners;
	private final ArrayList<WaterMeasurementRemovedListener> _waterMeasurementRemovedListeners;
	private final String SQL_ADD = "INSERT INTO water_measurement VALUES ( ? )",
			SQL_DELETE = "DELETE FROM water_measurement WHERE id = ?",
			SQL_GET_ALL = "SELECT * FROM action NATURAL JOIN water_measurement",
			SQL_GET_BY_ID = "SELECT * FROM action NATURAL JOIN water_measurement WHERE id = ?",
			SQL_GET_BY_AQUARIUM_ID = "SELECT * FROM action NATURAL JOIN water_measurement WHERE aquarium_id = ?";
	private boolean _allCached;
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Constructors">
	public WaterMeasurementTable()
	{
		_waterMeasurementAddedListeners = new ArrayList<WaterMeasurementAddedListener>();
		_waterMeasurementRemovedListeners = new ArrayList<WaterMeasurementRemovedListener>();
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Public Methods">
	//<editor-fold defaultstate="collapsed" desc="SQL add">
	@Override
	public Integer add(Object[] args) throws SQLException
	{
		Integer out = super.add(args);
		if (out != -1)
		{
			synchronized (getRows())
			{
				PreparedStatement st = Database.prepareStatement(SQL_ADD);
				st.setInt(1, out);

				try
				{
					if (st.executeUpdate() == 1)
					{
						_allCached = false;
						ActionRow actionRow = getByPrimaryKey(out);
						_allCached = true;
						fireWaterMeasurementAdded((WaterMeasurementRow) actionRow);
					}
					else
					{
						out = -1;
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return out;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL delete">
	@Override
	public boolean delete(Integer id) throws SQLException
	{
		boolean result = false;
		if (id != null
				&& id > 0)
		{
			synchronized (getRows())
			{
				ActionRow actionRow = getByPrimaryKey(id);
				Database.getWaterMeasurementListTable().deleteByMeasurementID(id);

				PreparedStatement st = Database.prepareStatement(SQL_DELETE);
				st.setInt(1, id);

				try
				{
					if (st.executeUpdate() == 1
							&& super.delete(id))
					{
						result = true;
						fireWaterMeasurementRemoved((WaterMeasurementRow) actionRow);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return result;
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="SQL get">
	@Override
	public Collection<ActionRow> getAll() throws SQLException
	{
		PreparedStatement st = Database.prepareStatement(SQL_GET_ALL);
		synchronized (getRows())
		{
			if (!_allCached)
			{
				try
				{
					ResultSet query = st.executeQuery();

					while (query.next())
					{
						put(new WaterMeasurementRow(query));
					}
					_allCached = true;
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
			return getRows().values();
		}
	}

	@Override
	public ActionRow getByPrimaryKey(Integer id) throws SQLException
	{
		WaterMeasurementRow waterMeasurementRow = null;
		if (id != null && id >= 0)
		{
			synchronized (getRows())
			{
				waterMeasurementRow = (WaterMeasurementRow) getRows().get(id);
				if (waterMeasurementRow != null || _allCached)
				{
					return waterMeasurementRow;
				}

				PreparedStatement st = Database.prepareStatement(SQL_GET_BY_ID);
				st.setInt(1, id);

				try
				{
					ResultSet query = st.executeQuery();
					if (query.next())
					{
						waterMeasurementRow = new WaterMeasurementRow(query);
						put(waterMeasurementRow);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return waterMeasurementRow;
	}

	@Override
	public ArrayList<ActionRow> getByAquariumId(int id) throws SQLException
	{
		ArrayList<ActionRow> out = new ArrayList<ActionRow>();
		synchronized (getRows())
		{
			if (_allCached)
			{
				for (ActionRow actionRow : getRows().values())
				{
					if (actionRow.getAquarium().getId() == id)
					{
						out.add(actionRow);
					}
				}
			}
			else
			{
				PreparedStatement st = Database.prepareStatement(SQL_GET_BY_AQUARIUM_ID);
				st.setInt(1, id);

				try
				{
					ResultSet query = st.executeQuery();
					while (query.next())
					{
						WaterMeasurementRow waterMeasurementRow = new WaterMeasurementRow(query);
						put(waterMeasurementRow);
						out.add(waterMeasurementRow);
					}
				}
				catch (SQLException ex)
				{
					throw ex;
				}
				finally
				{
					st.close();
				}
			}
		}
		return out;
	}
	//</editor-fold>
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Events">
	//<editor-fold defaultstate="collapsed" desc="Added">
	@Override
	public void addWaterMeasurementAddedEventListener(
			WaterMeasurementAddedListener listener)
	{
		synchronized (_waterMeasurementAddedListeners)
		{
			_waterMeasurementAddedListeners.add(listener);
		}
	}

	@Override
	public void removeWaterMeasurementAddedEventListener(
			WaterMeasurementAddedListener listener)
	{
		synchronized (_waterMeasurementAddedListeners)
		{
			_waterMeasurementAddedListeners.remove(listener);
		}
	}

	private void fireWaterMeasurementAdded(WaterMeasurementRow row)
	{
		synchronized (_waterMeasurementAddedListeners)
		{
			for (WaterMeasurementAddedListener listener : _waterMeasurementAddedListeners)
			{
				listener.waterMeasurementAdded(row);
			}
		}
	}
	//</editor-fold>

	//<editor-fold defaultstate="collapsed" desc="Removed">
	@Override
	public void addWaterMeasurementRemovedEventListener(
			WaterMeasurementRemovedListener listener)
	{
		synchronized (_waterMeasurementRemovedListeners)
		{
			_waterMeasurementRemovedListeners.add(listener);
		}
	}

	@Override
	public void removeWaterMeasurementRemovedEventListener(
			WaterMeasurementRemovedListener listener)
	{
		synchronized (_waterMeasurementRemovedListeners)
		{
			_waterMeasurementRemovedListeners.remove(listener);
		}
	}

	private void fireWaterMeasurementRemoved(WaterMeasurementRow row)
	{
		synchronized (_waterMeasurementRemovedListeners)
		{
			for (WaterMeasurementRemovedListener listener : _waterMeasurementRemovedListeners)
			{
				listener.waterMeasurementRemoved(row);
			}
		}
	}
	//</editor-fold>
	//</editor-fold>
}
